package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.cache.CategoryCache;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.client.search.SearchClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.QuestionFormDTO;
import com.tianji.learning.domain.po.InteractionQuestion;
import com.tianji.learning.domain.po.InteractionReply;
import com.tianji.learning.domain.query.QuestionAdminPageQuery;
import com.tianji.learning.domain.query.QuestionPageQuery;
import com.tianji.learning.domain.vo.QuestionAdminVO;
import com.tianji.learning.domain.vo.QuestionVO;
import com.tianji.learning.mapper.InteractionQuestionMapper;
import com.tianji.learning.mapper.InteractionReplyMapper;
import com.tianji.learning.service.IInteractionQuestionService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 互动提问的问题表 服务实现类
 * </p>
 *
 * @author EllieHy
 * @since 2024-06-01
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class InteractionQuestionServiceImpl extends ServiceImpl<InteractionQuestionMapper, InteractionQuestion> implements IInteractionQuestionService {
	public static final long NULL_TOTAL = 0L;
	public static final long NULL_PAGES = 0L;
	private final UserClient userClient;
	private final SearchClient searchClient;
	private final CourseClient courseClient;
	private final CatalogueClient catalogueClient;
	private final CategoryCache categoryCache;
	private final InteractionReplyMapper replyMapper;
	
	@Override
	@Transactional
	public void saveQuestion(QuestionFormDTO questionDTO) {
		// 1.获取登录用户
		Long userId = UserContext.getUser();
		// 2.数据转换
		InteractionQuestion question = BeanUtils.toBean(questionDTO, InteractionQuestion.class);
		// 3.补充数据
		question.setUserId(userId);
		// 4.保存问题
		save(question);
	}
	
	@Override
	@Transactional
	public void updateQuestion(Long id, QuestionFormDTO questionFormDTO) {
		//1.校验
		if (StringUtils.isBlank(questionFormDTO.getTitle())
				|| StringUtils.isBlank(questionFormDTO.getDescription())
				|| questionFormDTO.getAnonymity() == null) {
			throw new RuntimeException("参数错误");
		}
		if (getById(id) == null) {
			throw new RuntimeException("非法参数");
		}
		//获取登录用户
		Long userId = UserContext.getUser();
		if (!userId.equals(getById(id).getUserId())) {
			throw new RuntimeException("不能修改别人的互动问题");
		}
		//2.DTO转PO
		InteractionQuestion question = new InteractionQuestion();
		question.setDescription(questionFormDTO.getDescription());
		question.setTitle(questionFormDTO.getTitle());
		question.setAnonymity(questionFormDTO.getAnonymity());
		question.setId(id);
		updateById(question);
	}
	
	/**
	 * @param query 分页查询,包含课程id 小节id 和是否只查询我的问题
	 * @return 封装的分页数据
	 */
	@Override
	public PageDTO<QuestionVO> queryQuestionPage(QuestionPageQuery query) {
		//1.校验课程id
		if (query.getCourseId() == null) {
			throw new RuntimeException("课程id不能为空");
		}
		//2.获取登录用户id
		Long userId = UserContext.getUser();
		//3.分页查询  条件 courseId  onlyMine为true才会填充userId 小节id不为空则填充小节id  hidden为不隐藏,根据时间倒序
		Page<InteractionQuestion> page = lambdaQuery()
				.select(InteractionQuestion.class, info -> !info.getProperty().equals("description"))
				.eq(InteractionQuestion::getCourseId, query.getCourseId())
				.eq(query.getOnlyMine(), InteractionQuestion::getUserId, userId)
				.eq(query.getSectionId() != null, InteractionQuestion::getSectionId, query.getSectionId())
				.eq(InteractionQuestion::getHidden, false)
				.page(query.toMpPageDefaultSortByCreateTimeDesc());
		List<InteractionQuestion> records = page.getRecords();
		if (CollUtils.isEmpty(records)) {
			return PageDTO.empty(page);
		}
		
		Set<Long> latestAnswerIds = records.stream()
				.map(InteractionQuestion::getLatestAnswerId)
				.filter(Objects::nonNull)
				.collect(Collectors.toSet());
		Set<Long> userIds = records.stream()
				.filter(c -> !c.getAnonymity())
				.map(InteractionQuestion::getUserId)
				.collect(Collectors.toSet());
		
		//4.根据最新回答id,批量查询回答信息 条件 In id集合
		Map<Long, InteractionReply> replyMap = new HashMap<>();
		//集合有可能为空做一下非空判断
		if (CollUtils.isNotEmpty(latestAnswerIds)) {
			List<InteractionReply> replyList = replyMapper.selectBatchIds(latestAnswerIds);
			// 使用Stream处理列表成一个map
			replyMap = replyList.stream()
					.collect(Collectors.toMap(InteractionReply::getQuestionId, c -> c));
			// 同时收集非匿名用户的ID
			userIds.addAll(replyList.stream()
					.filter(r -> !r.getAnonymity())
					.map(InteractionReply::getUserId)
					.collect(Collectors.toList()));
		}
		//5.远程调用用户服务,查询用户信息  批量
		userIds.remove(null);
		Map<Long, UserDTO> userMap = new HashMap<>(userIds.size());
		if (CollUtils.isNotEmpty(userIds)) {
			List<UserDTO> users = userClient.queryUserByIds(userIds);
			userMap = users.stream()
					.collect(Collectors.toMap(UserDTO::getId, u -> u));
		}
		// 4.封装VO
		Map<Long, UserDTO> finalUserMap = userMap;
		Map<Long, InteractionReply> finalReplyMap = replyMap;
		List<QuestionVO> voList = records.stream().map(r -> {
			// 4.1.将PO转为VO
			QuestionVO vo = BeanUtils.copyBean(r, QuestionVO.class);
			// 4.2.封装提问者信息
			Optional.ofNullable(finalUserMap.get(r.getUserId()))
					.filter(userDTO -> !r.getAnonymity())
					.ifPresent(userDTO -> {
						vo.setUserName(userDTO.getName());
						vo.setUserIcon(userDTO.getIcon());
					});
			// 4.3.封装最近一次回答的信息
			Optional.ofNullable(finalReplyMap.get(r.getLatestAnswerId()))
					.ifPresent(reply -> {
						vo.setLatestReplyContent(reply.getContent());
						Optional.ofNullable(finalUserMap.get(reply.getUserId()))
								.filter(user -> !reply.getAnonymity())
								.ifPresent(user -> vo.setLatestReplyUser(user.getName()));
					});
			return vo;
		}).collect(Collectors.toList());
		return PageDTO.of(page, voList);
	}
	
	/**
	 * @param id 问题id
	 * @return QuestionVo
	 */
	@Override
	public QuestionVO queryQuestionById(Long id) {
		//1.校验
		if (id == null) {
			throw new BizIllegalException("非法参数");
		}
		//2.主键查询互动问题表
		InteractionQuestion question = this.getById(id);
		if (question == null) {
			throw new BizIllegalException("问题不存在");
		}
		//3.如果管理员隐藏则返回空
		if (question.getHidden()) {
			return null;
		}
		//4.封装数据返回
		QuestionVO vo = BeanUtils.copyBean(question, QuestionVO.class);
		// 5. 远程调用用户服务，查询用户信息并封装
		Optional.ofNullable(userClient.queryUserById(question.getUserId()))
				.filter(userDTO -> !question.getAnonymity())
				.ifPresent(userDTO -> {
					vo.setUserName(userDTO.getName());
					vo.setUserIcon(userDTO.getIcon());
				});
		return vo;
	}
	
	@Override
	public PageDTO<QuestionAdminVO> queryQuestionAdminVoPage(QuestionAdminPageQuery query) {
		//0.远程调用Search服务,根据课程名获取课程id
		String courseName = query.getCourseName();
		List<Long> cIds = Optional.ofNullable(courseName)
				.filter(StringUtils::isNotBlank)
				.map(searchClient::queryCoursesIdByName)
				.filter(CollUtils::isNotEmpty)
				.orElseGet(Collections::emptyList);
		
		if (cIds.isEmpty()) {
			return PageDTO.empty(NULL_TOTAL, NULL_PAGES);
		}
		
		//1.查询问题互动表, 前端传参数就查,不传就查全部
		Page<InteractionQuestion> page = lambdaQuery()
				.in(InteractionQuestion::getCourseId, cIds)
				.eq(query.getStatus() != null, InteractionQuestion::getStatus, query.getStatus())
				.between(query.getBeginTime() != null && query.getEndTime() != null,
						InteractionQuestion::getCreateTime,
						query.getBeginTime(), query.getEndTime())
				.page(query.toMpPageDefaultSortByCreateTimeDesc());
		List<InteractionQuestion> records = page.getRecords();
		if (CollUtils.isEmpty(records)) {
			return PageDTO.empty(NULL_TOTAL, NULL_PAGES);
		}
		//获取用户id集合  课程id集合  章节id集合 小节id
		Set<Long> userIds = records.stream().map(InteractionQuestion::getUserId).collect(Collectors.toSet());
		Set<Long> courseIds = records.stream().map(InteractionQuestion::getCourseId).collect(Collectors.toSet());
		Set<Long> chapterIds = records.stream().map(InteractionQuestion::getChapterId).collect(Collectors.toSet());
		//2.远程调用用户服务,获取用户信息
		List<UserDTO> userDtoS = userClient.queryUserByIds(userIds);
		if (CollUtils.isEmpty(userDtoS)) {
			throw new BizIllegalException("用户不存在");
		}
		Map<Long, UserDTO> userDtoMap = userDtoS.stream().collect(Collectors.toMap(UserDTO::getId, u -> u));
		//3.远程查询课程服务,获取课程信息
		List<CourseSimpleInfoDTO> courseSimpleInfoDtoS = courseClient.getSimpleInfoList(courseIds);
		if (CollUtils.isEmpty(courseSimpleInfoDtoS)) {
			throw new BizIllegalException("课程不存在");
		}
		Map<Long, CourseSimpleInfoDTO> cInfoDto =
				courseSimpleInfoDtoS.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
		//4.远程查询课程服务,获取章节信息
		List<CataSimpleInfoDTO> cataInfoDtoS = catalogueClient.batchQueryCatalogue(chapterIds);
		if (CollUtils.isEmpty(cataInfoDtoS)) {
			throw new BizIllegalException("章节不存在");
		}
		Map<Long, String> cataInfoDtoMap =
				cataInfoDtoS.stream().collect(Collectors.toMap(CataSimpleInfoDTO::getId, CataSimpleInfoDTO::getName));
		
		//5封装Vo返回
		List<QuestionAdminVO> voList = records.stream()
				.map(r -> {
					QuestionAdminVO vo = BeanUtils.copyBean(r, QuestionAdminVO.class);
					// 用户信息
					Optional.ofNullable(userDtoMap.get(r.getUserId()))
							.ifPresent(userDTO -> vo.setUserName(userDTO.getName()));
					
					// 课程信息
					Optional.ofNullable(cInfoDto.get(r.getCourseId()))
							.ifPresent(courseDTO -> {
								vo.setCourseName(courseDTO.getName());
								vo.setCategoryName(categoryCache.getCategoryNames(courseDTO.getCategoryIds()));
							});
					// 章信息
					vo.setSectionName(cataInfoDtoMap.get(r.getSectionId()));
					
					// 节信息
					vo.setCategoryName(cataInfoDtoMap.get(r.getChapterId()));
					return vo;
				})
				.collect(Collectors.toList());
		
		return PageDTO.of(page, voList);
	}
	
	@Override
	public QuestionAdminVO queryQuestionByIdAdmin(Long id) {
		// 1.根据id查询问题
		InteractionQuestion question = getById(id);
		if (question == null) {
			return null;
		}
		// 2.转PO为VO
		QuestionAdminVO vo = BeanUtils.copyBean(question, QuestionAdminVO.class);
		// 3.查询提问者信息
		UserDTO user = userClient.queryUserById(question.getUserId());
		if (user != null) {
			vo.setUserName(user.getName());
		}
		// 4.查询课程信息
		CourseFullInfoDTO cInfo = courseClient.getCourseInfoById(
				question.getCourseId(), false, true);
		Optional.ofNullable(cInfo)
				.ifPresent(c -> {
					vo.setCourseName(c.getName());
					vo.setCategoryName(categoryCache.getCategoryNames(c.getCategoryIds()));
					List<Long> teacherIds = c.getTeacherIds();
					Optional.ofNullable(userClient.queryUserByIds(teacherIds))
							.filter(CollUtils::isNotEmpty)
							.ifPresent(t -> vo.setTeacherName(t.stream()
							  		.map(UserDTO::getName).collect(Collectors.joining("/"))));
  				});
		// 5.查询章节信息
		List<CataSimpleInfoDTO> cateS = catalogueClient.batchQueryCatalogue(
				List.of(question.getChapterId(), question.getSectionId()));
		Map<Long, String> cataMap = new HashMap<>(cateS.size());
		if (CollUtils.isNotEmpty(cateS)) {
			cataMap = cateS.stream()
					.collect(Collectors.toMap(CataSimpleInfoDTO::getId, CataSimpleInfoDTO::getName));
		}
		vo.setChapterName(cataMap.getOrDefault(question.getChapterId(), ""));
		vo.setSectionName(cataMap.getOrDefault(question.getSectionId(), ""));
		// 6.封装VO
		return vo;
	}
	
	@Override
	public void hiddenQuestion(Long id, Boolean hidden) {
		// 1.更新问题
		InteractionQuestion question = new InteractionQuestion();
		question.setId(id);
		question.setHidden(hidden);
		updateById(question);
	}
	
	
	@Override
	@Transactional
	public void deleteById(Long id) {
		// 1.获取当前登录用户
		Long userId = UserContext.getUser();
		// 2.查询当前问题
		InteractionQuestion q = getById(id);
		if (q == null) {
			return;
		}
		// 3.判断是否是当前用户的问题
		if (!q.getUserId().equals(userId)) {
			// 不是，抛出异常
			throw new BadRequestException("无权删除他人的问题");
		}
		// 4.删除问题
		removeById(id);
		// 5.删除答案
		replyMapper.delete(
				new QueryWrapper<InteractionReply>().lambda().eq(InteractionReply::getQuestionId, id)
		);
	}
}
